package cn.psvmc.cxzapi.service.order;

import cn.psvmc.cxzapi.config.ConfigKey;
import cn.psvmc.cxzapi.config.mybatisplus.service.impl.AbstractService;
import cn.psvmc.cxzapi.exception.ServiceException;
import cn.psvmc.cxzapi.mapper.order.*;
import cn.psvmc.cxzapi.model.common.OrderEntity;
import cn.psvmc.cxzapi.model.order.*;
import cn.psvmc.cxzapi.service.system.ServiceUtil;
import cn.psvmc.cxzapi.util.ToolUtils;
import cn.psvmc.cxzapi.util.delivery.DbAPIService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;

/**
 * 订单快递表 服务实现类
 * @Author auto
 * @Date 2024-08-12
 */
@Service
@Slf4j
public class TOrderDeliveryService extends AbstractService<TOrderDeliveryMapper, TOrderDelivery> {

    @Resource
    private TOrderDeliveryMapper tOrderDeliveryMapper;
    @Resource
    private ServiceUtil serviceUtil;
    @Resource
    private TOrderMapper orderMapper;
    @Resource
    private TOrderDeliveryRecordMapper tOrderDeliveryRecordMapper;
    @Resource
    private TOrderLogService orderLogService;
    @Resource
    private TOrderBillMapper orderBillMapper;
    //读写锁（多个线程可以同时持有读锁，但只能有一个线程持有写锁。适用于读多写少的场景）
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();

    /**
     * @Description 发货
     * @Date 2024/9/7 18:45
     * @Author YWX
     * @Param [tOrderDelivery]
     * @Return void
     **/
    public void add(TOrderDelivery tOrderDelivery) {
        rwLock.readLock().lock();
        String code = tOrderDelivery.getOrderCode();
        tOrderDelivery.setDispatchTime(LocalDateTime.now());
        Integer deliveryType = tOrderDelivery.getDeliveryType();
        String trackingCode = tOrderDelivery.getTrackingCode();
        if (deliveryType.equals(99)) {
            tOrderDelivery.setTrackingCode("");
        }
        TOrder order;
        TOrderDelivery od;
        try {
            order = orderMapper.selectByOrderCode(tOrderDelivery.getOrderCode());
            if (order == null) {
                throw new ServiceException("订单不存在！");
            }
            od = tOrderDeliveryMapper.findByCodeAndType(code, tOrderDelivery.getType());
        } finally {
            rwLock.readLock().unlock();
        }
        rwLock.writeLock().lock();
        try {
            boolean isNew = true;//是否是新的快递单号
            if (od != null) {
                if (od.getDeliveryType().equals(99) && deliveryType.equals(99)) {
                    isNew = false;
                } else if (od.getDeliveryType().equals(deliveryType) && od.getTrackingCode().equals(trackingCode)) {
                    isNew = false;
                } else {
                    tOrderDelivery.setOdid(od.getOdid());
                    tOrderDeliveryRecordMapper.deleteByOdId(tOrderDelivery.getOdid());//删除订单快递记录
                    tOrderDeliveryMapper.updateById(tOrderDelivery);
                }
            } else {
                tOrderDeliveryMapper.insert(tOrderDelivery);
            }
            if (order.getOrderStatus().equals(2)) {//订单待发货改订单状态为已发货
                orderMapper.updateDeliveryStatus(code);
            }
            if (isNew && !deliveryType.equals(99)) {
                standTraceSubscribe(deliveryType, Collections.singletonList(tOrderDelivery));//标准轨迹订阅
            }

            /*if (tOrderDelivery.getType().equals(1) && deliveryType.equals(99)) {
                int leaseFixed = 1;
                String acceptTime = order.getCreatetime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                Integer orderId = order.getOrderId();
                LocalDateTime realBegin = order.getRealBegin();
                LocalDateTime realEnd = order.getRealEnd();
                updateOrderLease2(leaseFixed, acceptTime, orderId, realBegin, realEnd);
            }*/
        } finally {
            rwLock.writeLock().unlock();
        }

        //发货日志
        TOrderLog orderLog = new TOrderLog();
        orderLog.setOrderCode(code);
        orderLog.setLogType("修改单号");
        String type;
        if (tOrderDelivery.getType().equals(1)) {
            type = "订单发货";
        } else {
            type = "订单归还";
        }
        if (deliveryType.equals(99)) {
            type += "，自提";
        } else {
            type += "，快递单号：" + trackingCode;
        }
        orderLog.setComm(type);
        orderLogService.saveOrderLog2(orderLog);
    }

    /**
     * @Description 物流信息
     * @Date 2024/8/23 12:24
     * @Author YWX
     * @Param [tOrderDelivery]
     * @Return java.lang.String
     **/
    public Map<String, Object> detail(String orderCode, Integer type) {
        Map<String, Object> map = serviceUtil.detailDelivery(orderCode, type);
        /*if (map != null && map.get("leaseFixed").equals(1) && map.get("oldLeaseFixed").equals(0)) {
            updateOrderLease2(1, ToolUtils.objToString(map.get("acceptTime")), ToolUtils.objToInteger(map.get("orderId"))
                    , (LocalDateTime) map.get("realBegin"), (LocalDateTime) map.get("realEnd"));
        }*/
        return map;
    }

    /**
     * @Description 发货工作台
     * @Date 2024/8/23 12:27
     * @Author YWX
     * @Param [iPage, entity]
     * @Return com.baomidou.mybatisplus.core.metadata.IPage<java.util.Map>
     **/
    public IPage<Map> list(Page<TOrderDelivery> iPage, OrderEntity entity) {
        entity.setStoreid(serviceUtil.getStoreId());
        return tOrderDeliveryMapper.listAll(iPage, entity);
    }

    /**
     * @Description 批量发货
     * @Date 2024/8/23 12:21
     * @Author YWX
     * @Param [tOrderDelivery]
     * @Return void
     **/
    public void batchAdd(TOrderDelivery tOrderDelivery) {
        Integer deliveryType;
        List<TOrderDelivery> addDelivery;
        List<TOrderDelivery> updateDelivery;
        List<TOrderDelivery> list = new ArrayList<>();
        rwLock.readLock().lock();
        try {
            deliveryType = tOrderDelivery.getDeliveryType();
            String[] orderCodes = tOrderDelivery.getOrderCode().split("\n");
            TOrderDelivery od;
            for (String order : orderCodes) {
                if (ToolUtils.isEmpty(order)) {
                    continue;
                }
                od = new TOrderDelivery();
                String[] code = ToolUtils.replaceMultipleSpaces(order).split(" ");
                if (deliveryType.equals(99)) {
                    od.setTrackingCode("");
                    if (ToolUtils.isEmpty(code[0])) {
                        continue;
                    }
                } else {
                    if (code.length != 2) {
                        throw new ServiceException("订单号和快递单号不匹配！");
                    } else if (ToolUtils.isEmpty(code[0]) || ToolUtils.isEmpty(code[1])) {
                        throw new ServiceException("订单号或快递单号不能为空！");
                    }
                    od.setTrackingCode(code[1]);
                }
                od.setOrderCode(code[0]);
                od.setDeliveryType(deliveryType);
                od.setDispatchTime(LocalDateTime.now());
                list.add(od);
            }
            List<TOrderDelivery> list2 = tOrderDeliveryMapper.checkOrderCode(list);
            List<String> notExistOrder = new ArrayList<>();
            List<String> notCheckedOrder = new ArrayList<>();
            addDelivery = new ArrayList<>();
            updateDelivery = new ArrayList<>();
            for (TOrderDelivery o : list2) {
                String orderCode = o.getOrderCode();
                Integer orderStatus = o.getOrderStatus();
                Integer odid = o.getOdid();
                String trackingCode = o.getTrackingCode();
                TOrderDelivery o2 = list.stream().filter(t -> t.getOrderCode().equals(orderCode)).findFirst().orElse(null);
                if (ToolUtils.isEmpty(o.getOrderId())) {
                    notExistOrder.add(orderCode);
                } else if ((!orderStatus.equals(2) && !orderStatus.equals(3))) {
                    notCheckedOrder.add(orderCode);
                } else if ((!deliveryType.equals(99) && ToolUtils.isTrueInteger(odid) && !o2.getTrackingCode().equals(trackingCode))
                        || (deliveryType.equals(99) && ToolUtils.isNotEmpty(trackingCode))) {
                    o2.setOdid(odid);
                    updateDelivery.add(o2);
                } else if (!ToolUtils.isTrueInteger(o.getDeliveryType())) {
                    addDelivery.add(o2);
                }
            }
            if (ToolUtils.isListNotEmpty(notExistOrder)) {
                throw new ServiceException("订单号：" + String.join(",", notExistOrder) + "不存在！");
            }
            if (ToolUtils.isListNotEmpty(notCheckedOrder)) {
                throw new ServiceException("订单号：" + String.join(",", notCheckedOrder) + "不满足发货条件！");
            }
        } finally {
            rwLock.readLock().unlock();
        }
        boolean addLog = false;
        List<TOrderDelivery> addOrUpdateDelivery = new ArrayList<>();
        rwLock.writeLock().lock();
        try {
            if (ToolUtils.isListNotEmpty(addDelivery)) {
                saveBatch(addDelivery);
                /*for (TOrderDelivery delivery : addDelivery) {
                    if (delivery.getDeliveryType().equals(99)) {
                        int leaseFixed = 1;
                        TOrder order = orderMapper.selectByOrderCode(delivery.getOrderCode());
                        String acceptTime = order.getCreatetime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                        Integer orderId = order.getOrderId();
                        LocalDateTime realBegin = order.getRealBegin();
                        LocalDateTime realEnd = order.getRealEnd();
                        updateOrderLease2(leaseFixed, acceptTime, orderId, realBegin, realEnd);
                    }
                }*/
                standTraceSubscribe(deliveryType, addDelivery);//标准轨迹订阅

                addLog = true;
                addOrUpdateDelivery.addAll(addDelivery);
            }
            if (ToolUtils.isListNotEmpty(updateDelivery)) {
                List<Integer> odIds = updateDelivery.stream().map(TOrderDelivery::getOdid).collect(Collectors.toList());
                if (ToolUtils.isListNotEmpty(odIds)) tOrderDeliveryRecordMapper.deleteByOdIds(odIds);//删除订单快递记录
                updateBatchById(updateDelivery);
                standTraceSubscribe(deliveryType, updateDelivery);//标准轨迹订阅
                addLog = true;
                addOrUpdateDelivery.addAll(updateDelivery);
            }
            String codes = list.stream().map(TOrderDelivery::getOrderCode).collect(Collectors.joining("','"));
            orderMapper.updateDeliveryStatus(codes);
        } finally {
            rwLock.writeLock().unlock();
        }
        if (addLog) batchSaveLog(addOrUpdateDelivery);//批量保存发货日志
    }

    //批量保存发货日志
    private void batchSaveLog(List<TOrderDelivery> deliveries) {
        List<TOrderLog> logs = new ArrayList<>();
        for (TOrderDelivery orderDelivery : deliveries) {
            //发货日志
            TOrderLog orderLog = new TOrderLog();
            orderLog.setOrderCode(orderDelivery.getOrderCode());
            orderLog.setLogType("批量发货");
            String comm;
            if (orderDelivery.getDeliveryType().equals(99)) {
                comm = "订单发货，自提";
            } else {
                comm = "订单发货，快递单号：" + orderDelivery.getTrackingCode();
            }
            orderLog.setComm(comm);
            logs.add(orderLog);
        }
        orderLogService.batchSaveOrderLog(logs);
    }

    //标准轨迹订阅
    private void standTraceSubscribe(Integer deliveryType, List<TOrderDelivery> addDelivery) {
        if (deliveryType.equals(2)) {//德邦
            if (!ConfigKey.enableSubscribe) return;
            for (TOrderDelivery orderDelivery : addDelivery) {
                DbAPIService.standTraceSubscribe(orderDelivery.getOrderCode(), orderDelivery.getTrackingCode());
            }
        } else if (deliveryType.equals(1)) {//顺丰
            for (TOrderDelivery orderDelivery : addDelivery) {
                Integer type = orderDelivery.getType();
                if (!ToolUtils.isTrueInteger(type)) {
                    type = 1;
                }
                serviceUtil.detailDelivery(orderDelivery.getOrderCode(), type);
            }
        }
    }

    /**
     * @Description 德邦标准轨迹保存
     * @Date 2024/9/30 11:11
     * @Author YWX
     * @Param [params]
     * @Return void
     **/
    @Async("asyncPoolTaskExecutor")
    public void saveDbTrace(String params) throws JsonProcessingException {
        if (ToolUtils.isEmpty(params)) {
            return;
        }
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode rootNode = objectMapper.readTree(params);
        if (rootNode == null) {
            return;
        }
        List<Map<String, Object>> records;

        int leaseFixed = 0;
        String acceptTime = "";
        // 遍历 track_list
        for (JsonNode trackNode : rootNode.get("track_list")) {
            String trackingNumber = trackNode.get("tracking_number").asText();
            records = new ArrayList<>();
            for (JsonNode traceNode : trackNode.get("trace_list")) {
                String status = DbAPIService.getDeliveryStatus(traceNode.get("status").asText());
                String comm = "";
                Map<String, Object> record = Map.of(
                        "remark", status,
                        "acceptTime", getJsonNodeText(traceNode, "time"),
                        "comm", getJsonNodeText(traceNode, "city") + getJsonNodeText(traceNode, "site") + getJsonNodeText(traceNode, "description")
                );
                if (status.contains("签收")) {
                    leaseFixed = 1;
                    acceptTime = traceNode.get("time").asText();
                }
                records.add(record);
            }
            if (ToolUtils.isListNotEmpty(records)) {
                List<TOrderDelivery> deliveries = tOrderDeliveryMapper.listOdIdByTrackingCode(2, trackingNumber);//根据快递单号查询订单快递id
                for (TOrderDelivery delivery : deliveries) {
                    tOrderDeliveryRecordMapper.insertBatch(records, delivery.getOdid());
                    /*if (delivery.getType().equals(1) && leaseFixed == 1) {
                        TOrder order = orderMapper.selectByOrderCode(delivery.getOrderCode());
                        Integer orderId = order.getOrderId();
                        LocalDateTime realBegin = order.getRealBegin();
                        LocalDateTime realEnd = order.getRealEnd();
                        updateOrderLease2(leaseFixed, acceptTime, orderId, realBegin, realEnd);
                    }*/
                }
            }
        }
    }

    //获取JsonNode值
    private String getJsonNodeText(JsonNode node, String key) {
        if (node.has(key)) {
            return node.get(key).asText();
        } else {
            return "";
        }
    }

    //更新租期
    /*@Async("asyncPoolTaskExecutor")
    public void updateOrderLease2(Integer leaseFixed, String acceptTime, Integer orderId, LocalDateTime realBegin, LocalDateTime realEnd) {
        LocalDate beginDate = LocalDate.parse(acceptTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        LocalDateTime beginTime = beginDate.plusDays(1).atTime(00, 00, 00);
        long seconds = Duration.between(realBegin, beginTime).getSeconds();
        TOrder updateOrder = new TOrder();
        updateOrder.setOrderId(orderId);
        updateOrder.setRealBegin(beginTime);
        updateOrder.setRealEnd(realEnd.plusSeconds(seconds).minusSeconds(1));
        updateOrder.setLeaseFixed(leaseFixed);
        orderMapper.updateLeaseFixedById(updateOrder);
        orderBillMapper.updatePeriod2(orderId, seconds);
        TOrderDelivery tOrderDelivery = tOrderDeliveryMapper.findByOrderIdAndType(orderId, 1);
        tOrderDelivery.setAcceptTime(acceptTime);
        AlipayCreate.deliverySend(tOrderDelivery, orderMapper.getGoodsDetail(orderId));
    }*/

    /**
     * @Description 根据物流签收时间更新订单租期
     * @Date 2024/11/11 23:39
     * @Author YWX
     * @Param []
     * @Return void
     **/
    /*public void updateOrderLease(int deliveryType) {
        List<TOrderDelivery> list = tOrderDeliveryMapper.listOrder(deliveryType);//获取租期未固定订单列表
        for (TOrderDelivery delivery : list) {
            String acceptTime = delivery.getAcceptTime();
            List<Integer> deliveryTypes = new ArrayList<>();
            deliveryTypes.add(1);
            if (ConfigKey.enableSubscribe) {
                deliveryTypes.add(2);
            }
            if (ToolUtils.isEmpty(acceptTime) && deliveryTypes.contains(delivery.getDeliveryType()) && delivery.getTrackingCode().length() > 6) {
                Map<String, Object> detail = serviceUtil.detailDelivery(delivery.getOrderCode(), delivery.getType());
                if (detail == null) continue;
                if (detail.get("leaseFixed").equals(1)) {
                    acceptTime = ToolUtils.objToString(detail.get("acceptTime"));
                }
            }
            if (ToolUtils.isNotEmpty(acceptTime)) {
                updateOrderLease2(1, acceptTime, delivery.getOrderId(), delivery.getDispatchTime(), delivery.getCreatetime());
            }
        }
    }*/

    /**
     * @Description 获取发货工作台状态数量
     * @Date 2024/11/16 23:04
     * @Author YWX
     * @Param [entity]
     * @Return java.util.Map<java.lang.String, java.lang.Object>
     **/
    public Map<String, Object> getStatusNum(OrderEntity entity) {
        entity.setStoreid(serviceUtil.getStoreId());
        return tOrderDeliveryMapper.getStatusNum(entity);
    }
}
